The online racing simulator
Searching in All forums
(577 results)
Scawen
Developer
After a longer gap than usual there are a few things to report. Thumbs up

Soon after the last report, after fixing a few things that were sitting on lists, I added a new type of object that can be used in the track editor to connect up other objects more easily. Instead of the usual cross-sections connected by segments (with curves) this new system allows the simple addition of triangles. As if in the modeller, but between different cross-sections. It's hard to explain but it does simplify tasks by making it a lot easier to fill odd-shaped holes!

After my day of fixes on Fern Bay, Eric decided to have a quick go at it, really just fixes for the new lighting system. There were still some holes to fill, which are important for shadows, and he wanted to add some shine (specular effect) to the roads. He updated a few textures here and there in addition to the road surfaces but did the bare minimum of modelling. As stated before, there isn't time to bring Fern Bay up to the modern standard before the coming release, but it was certainly worth a few days tidying up.

After Eric sent me the update, I noticed a few remaining issues that I could improve with the use of new editor functions that I quickly coded. It is useful for me to spend a little time in the track editor because I often think of a few new functions or improvements to do.

Trying to get things finished can be a lengthy process! After the Fern Bay update we ended up taking on an extra task, almost by mistake. Eric wanted to update some of the layout objects which looked quite tired and old. His plan was just a few days brushing up a few objects. Quickly the task expanded and we started to make use of the new mapping configuration and monochrome colours system, that help maintain variety in the track editor, now extended to the layout objects. With a single object selected there can be several variations on the texture cutouts that are displayed. There was community involvement and we took on some of the ideas. There are definite benefits, so it was worth a week on the job. Even if that week turned out to be two weeks! We're near the end of layout updates for now!
Public thread about layout objects: https://www.lfs.net/forum/thread/101752

Eric and I have discussed the need to try to get to the release and only do what is necessary from now on. We want to do a lot of things but they can be done after the release. Smile

On my side I have another day or two on layout functions, and there are some editor features to look at that could help Eric complete South City. Sometimes when buildings follow the edges of existing roads they can end up quite complex and bring up issues that can be made easier by certain new editor functions. I enjoy doing editor functions but of course, I am trying to get off graphics to finish the tyre physics and get to that public beta as quickly as possible.


Log of updates:

Layout marshals also needed to pick up lighting from lightmap (objects already do)
- marshals are done a different way and do a single lightmap reading when first drawn

Improved track editor function for setting height of multiple points
- also generally updated initialisation of text entry to the new style in a few places

Added a new type of surface that can be added in the track editor
- an extension of "section end triangles" but now can connect to other cross-sections
- as arbitrary triangles between track objects they can make it easier to fill holes
- turned out this is was a bit more work than expected in the track editor
- when objects can refer to others a lot of care must be taken with delete functions

Fix: track editor bug - surface properties were not updated correctly when changed
Fix: a physics surface debug display was not using the thread-safe copy of wheels
Fix: suspension diagram was also not yet updated to use thread-safe variables
Fix: time could move on up to 30 sec in track editor then car would catch up on exit

Eric sent a minor update of Fern Bay with specular lighting added to road textures
- other small updates as well including filling all the holes as seen from above
- although it's not a full update these are important fixes for the shadow system
- also improved a few textures around that needed brightening up in addition to shine
- the general effect is improved as you can see in the attached screenshots

I spotted a few remaining Fern Bay issues and went into the track editor to fix them
- changed/added editor functions that helped with searching/updating multiple objects
- a benefit of me spending time in editor is I sometimes come up with useful functions

Eric started to do a quick update on the layout objects that would take a few days
- it is not really the highest priority but seemed like a quick improvement at first
- job got a little bigger as we added support for selectable "mapping configurations"
- these, along with a colour selector, allow more variety without more object slots
- so we can have e.g. more signs or cone colours using the new improved objects

Discussion with Eric about the new world triangles hole filling system
- it can help fill holes in South City, either large holes out of town or small holes
- Eric showed me some of the challenging things at South City to finish in a good way
- looking at the real situations that come up, we thought of some helpful improvements

Worked on the updated (and new) layout objects
- asked community members if they had suggestions for a few useful objects
- some useful things came from that thread: https://www.lfs.net/forum/thread/101752
- using the new mapping configurations and monochrome colours, more variety is possible
- with a single object selected, multiple configurations can be chosen (e.g. letters)
- in the screenshot you can see most of the new objects but not showing all variations
Scawen
Developer
To be clear, this is all for the development version and cannot be implemented into the current public version. There are still tracks and tyre physics to finish before it can be released.
Scawen
Developer
Quote from R-to :Example our SLADI Masters drifting series is building a lot real life racing track´s and we want to make them look and feel like the real thing. Like this TAMPERE, KAANAA CENTER circuit! Please Scawen, give us possibility make them feel and look nice as possible just making object´s in the layout editor and adding them in to the game.

I really feel for you but the layout editor will never do this properly. That's where you need a track editor!

Previous post: https://www.lfs.net/forum/post/2027832#post2027832

Quote from Racon :I think I'd prefer extra colours over ease of use, just to unleash people's creativity for colour-coding things. I've got a project on the go where I'm encoding a number in concrete colours as we speak Big grin


Is it in your scope to add a way to swap out a selected object with something new? I was thinking maybe if you had an object selected and ctrl-click a new object type from the menu, it could change the selected object's index without changing anything else.

We've decided to go for the 48 characters in a single object because it's really the right way to do it. Not some dodgy workaround that we'll be stuck with forever. When in the future we change to 16-byte objects instead of 8-byte, then we can do all the requests like micro heading and pitch adjustments, more colours, bigger concrete objects and so on. But there's just no way I can devote a few weeks to that now. Unless we all want the whole update delayed (we don't).

I'm referring to previous posts, not just you, Racon! Smile

While we all know layouts can go *further* it is really hard work and what we all really want is the new graphics and physics, right? After that we can do layout updates, other graphical things like improved skinnable drivers, maybe move to track editor (don't know what this may involve regarding licenses though, but that is another discussion I will NOT get involved in any time soon). And have no idea if that will ever happen, by the way. It's what I want to happen, but I don't make promises and specifically don't promise this.

Let's not change "layout week" into "layout month" OK! Big grin


Specifically on the character boards thing, I've suggested white and yellow as the most useful colours. It could be possible to add a straight copy of that entire object, with another two colours, if that would be particularly useful.
Last edited by Scawen, .
Scawen
Developer
Another 12 days have passed and some of you may be interested to read the log. The super short version is I've been fixing things, doing things that needed to be done, getting rid of lists of things to do. I'm trying to get all the important things out of the way ready to focus on tyre physics. Things that are less important, I plan to do after the release (apart from the odd thing here or there that I simply feel like doing).

The attached images show what tyre smoke looks like in a tunnel with and without a lightmap! Big grin


Log of changes:

Some small tasks to finish the delayed texture loading system
- updated per-frame task sequencer so if a car model was built a texture is not loaded
- renamed / reorganised some of the new functions to make more sense when reading code
- prevented delayed texture loading in modeller and vehicle editor (prefer instant)
- fixed single frame with headless driver standing up when exiting animation editor
- the option to switch between compressed and full skins now uses new reload system
- used MP replay to test switching between high and low resolution auto-download skins
- added critical section to make sure DDS saving cannot coincide with loading DDS skin

Spent a day on Fern Bay in the editor - various fixes (not creative work)
- unlike other tracks, Eric does not plan major Fern Bay updates in the near future
- there were shadow holes due to buildings and footbridges without top surfaces
- as an old favourite I wanted to see it in good condition suitable for release
- it's good for me to spend a little time in the track editor occasionally

Fixed minor issue: players joining in entry screen could trigger texture purge events
- host and guests did a quick load and delete of the new player's car to check setup
- as this car was loaded in "in-game" mode it would trigger a check for unused textures
- but cars no longer point to a setup in the player so this seemed to have no purpose
- so instead of preventing the cars triggering a texture purge, simply avoid this code

Off-topic interface update: Provide a left and right arrow for multi-state options
- it bugged me that to switch off replay saving I had to pass through an extra state
- now I can simply click left arrow to switch off saving / right arrow to enable
- the arrow button is greyed out if you reach the last option in that direction
- the 'greyed out' logic was easily applied to option slider bars so did that too
- tempting to do it for the integer nudge buttons but would have to change all calls
- too much to do so will forget that until the inconsistency bugs me in the future

Some development version updates
- new feature to help search for textures in the editor (in objects and world mappings)
- fixed system to load most recent version of a track for a lesson (not exact match)
- update to allow replays to load most recent version of a track (or currently loaded)
- fixed a thread protection notification exiting from editor using the window X button

Training lesson fixes
- fixed start time of training lessons which were always at midnight on 1 January 1601
- fixed some small issues around loading tracks that triggered thread warning messages
- fixed a "Game call from main thread" thread warning message during training lessons

General fixes
- fix for a thread protection notification when LFS does a full D3D recovery
(I have not seen a D3D recovery other than by deliberately forcing it to happen)

Fix for a problem noticed in MPR but would affect multiplayer generally
- symptom was a puff of smoke when clicking timeline to a certain point in the replay
- took a while to track down the cause (depended on where car was before fast forward)
- related to tyre's 'previous ground position' which is compared with current position
- this previous position was wrong if car was at a different angle before pos packet
- this has very minimal difference if pos packet is for a car that is currently viewed
- bigger difference if moving to a car that has not been viewed (physics not updated)
- solution is to get a good estimate for previous position using velocity and rotation
- testing shows that car velocity gives a good estimate so will leave out rotation now

The problem described above took me into angular momentum, rotation, position updates
- some things were still waiting since the 1000Hz updates (on my notes for months)
- now there is no sub-update, some things can be rearranged a little (for accuracy)
- a position accumulator is needed for low speeds (to avoid a 'minimum speed' issue)
- seems good to be pulling me back into physics as the tyre updates are waiting
- converted old variable FloatPos (was related to sub-updates) to position accumulator
- now super-slow speeds are possible and car cannot be stuck on 'digital rails' (xyz)

Have noticed an issue for some time - physics objects resisted starting to move
- seems to be related to 1000Hz update: object velocity not fast enough after 1 frame
- fixed by reducing the speed at which an object is considered to have started moving

Cleaned up code from recent changes / discarded finished notes / browsed old notes
- copied a few things from the old notes onto a short list of tasks to do for release
- although we are still a way from there I want to know what remains other than tyres
- random OT: made arrow keys work to move between options screens (seems like should)
- old notes reminded me that smoke particles do not pick up lighting from lightmap
- the lightmap stores info about artificial light and sky visibility, in an octree
- that means smoke looks black in the night and also too bright in tunnel during day
- made smoke particles read lightmap - see the attached images for before and after
Scawen
Developer
Hello everyone.

As you know, we are working hard and trying to get to the long awaited release. I've discussed a little with Eric about the need for us to try to bring our work to a close and really get to the release.

There's always a problem of wanting to do more but sometimes we need to wrap up what is done and get it out there.

So that's the aim. Currently I am trying to get the last notes off my lists of things to finish and bugs to fix, related to the 1000 Hz updates, multithreading and the lighting changes.

That will leave me with the tyre physics to dive into once again to figure out where it's strong, where it's weak, what parts need to be improved before the big release and what can be done later.

On Eric's side, I know he has been very involved with South City and its architecture, making a really beautiful area with so many ways to drive around. I guess he he will be able to delay some of the planned updates, to focus more on filling holes and there are also holes to fill at Kyoto.

In case you haven't seen already, there are a lot of pictures of South City and other new tracks on the 20th Anniversary report from August:
https://www.lfs.net/20th-anniversary

If you want to know what I have been doing, I have listed it in extreme detail on recent threads.

Multithreading progress: (not adding to this one)
https://www.lfs.net/forum/thread/100464-Progress-on-Multithreading

Development progress: (still ongoing)
https://www.lfs.net/forum/thread/101348-Development-Progress

So I think we are keeping you pretty well informed. I'm sure everyone can understand that it is in no way possible to finish everything before Christmas and we can't really think of a way to produce a new progress report at the moment.

But we are trying to get there as the release is very important! Smile

I will close this thread as it doesn't really serve a useful purpose any more.
Scawen
Developer
Another week has passed and I've got rid of some more sheets of paper. The bulk of the work was allowing textures to be loaded gradually after the car's 3D model has been built. Initially it was necessary to allow number plates to be updated without rebuilding the car, for the case of a player changing their number plate while their car is on the track. Sounds obscure, but it was the last case of the car mesh being fully rebuilt while already in game. The trick was to keep a different slot for each player so the text on that slot could be updated at any time, so the number plate can change without the car model even being notified.

More obviously important was a system to allow the textures to be loaded in a delayed manner after the car mesh is built. In recent versions, a remote car's model is built only when the car comes into view, but there is a slight glitch at that point (as there always has been). I've now reduced that a lot by initially using existing special system textures for white skins and grey textures, if the texture isn't already in memory. Then the textures are loaded in subsequent frames, one by one. That doesn't take long so now if you see a white car, it won't be for long, and the glitches will be less than they were before.

It probably doesn't sound very exciting but to me it has been quite interesting to see cars loading quickly then their textures rapidly appearing over the next few frames. But I've changed it so when you load a car in the garage or click on someone's car in the game setup screen, it is always an instant load. Also when entering the game in single player or a replay the cars can be fully loaded before presenting the first frame. But for multiplayer we want to get in there as fast as possible as all connected players must be in sync. So in that case you can see cars appearing sequentially (nearest first) then all their textures are loaded and finally the number plates update. It's a better feeling than the long hold on a black screen when everyone has clicked ready.

It seems like most of my immediate notes are going to the paper recycling now. I have to do something to separate the light direction into a physical side (could be used e.g. for track temperatures) and a graphical side. In future that could relate to other weather features. Just like everything else, the physical side needs to be updated by game code and the graphical side will represent or approximate that visually.

A few other things to do and a few bugs to fix, to give me a clear head then maybe I can look at some tyre physics and reassess that, figure out what needs to be adjusted or finished to get nearer to the long awaited release. Thumbs up


Log of changes:

Improved editor colours when showing grids, pit zones, start positions, checkpoints
- makes it easier to find checkpoints as they need to be adjusted on all tracks

Reduced size of vertices sent to GPU by using more efficient storage for normals
- this helps memory bandwidth when drawing each frame and reduces memory usage

Adjustment to number plate system to allow plate to be updated without rebuilding car
- although a rare event this was the last remaining use of old car mesh rebuild system
- previously used to rebuild after a skin download or after pit-out glitch reduction
- now the text can be updated on the number plate texture without car being notified

System to delay loading textures all at once when the car model is built
- this is to replace the old pit-out glitch reduction that had to be removed
- it was never very nice as it resulted in white cars until your own car stopped
- new system creates texture objects in memory initially using a grey system texture
- after the car is loaded, every frame just one car texture is loaded (if not already)
- it was simple enough for the standard dds textures (but complicated a bit by mods)
- more confusing is the use of skins / skins_dds / skins_x / skins_y / mod skin folder
- the trick is to store all settings that control texture load, in the texture object
- changed the temporary texture for skins to white (looks better with user set colours)
- the temporary texture for all other textures remains grey which seems to work well
- number plate textures not updated until next frame after the last texture is loaded
- now car load, model build, texture loads, number plate creation all done separately

Fixed off topic bug: With some vehicles, exposure was noticeably wrong on entering game
- turned out that driver was not created in car setup but only when vehicle first drawn
- so eye position was not available in advance of first frame (used a default position)
- in some vehicles this could put the view in a dark place so exposure turned right up
- a result of exposure adjusting to output image + recent changes to car initialisation
- exposure usually adjusts gradually but it goes instantly to the first frame exposure

Back to the pit-out glitch, the worst remaining glitch is creation of the car model
- much reduced as it does not include loading textures (because of the recent changes)
- more of an issue could be when more than one car model is built in a graphical frame
- for instance turning last corner into pit straight, after some cars joined the race
- seems it should be possible to only allow creation of one car's model in any frame
- this would spread the stutter over a few long frames instead of one really long frame
- tested this by enabling it when entering game - cars appear one by one up the grid
- it's a good test - cars can appear individually then textures appear individually
- now the thing is to stop it happening at times like single player grid or in garage
- nice for me to see the delayed load but it's better not to see that when not needed
Last edited by Scawen, . Reason : correction - the white and grey textures already exist (are not loaded)
Scawen
Developer
Eleven days since the last report, here is some more progress. Not much on multithreading but a couple of thread-related bug fixes. This period started with some work on the skin downloads which now work more smoothly and with a smaller glitch when the texture is applied to the car.

More interesting was an increase in the number of available objects. I had to overcome a technical limitation that object indices were 16-bit numbers, for historical reasons, which meant there was a hard limit of 65536 objects in the world. Objects mainly include actual objects, track cross-sections (we call them simply 'sections') and the segments that link sections, with curves and surfaces. Also flags, marshals, trees, and abstract objects like cameras, start points, grids and pit zones count as objects too.

The new South City has been getting close to that limit and I wanted to add a few more, which were related to an improved way of timing laps. Now that timing can be done to an accuracy of 0.001 seconds, the old path-based timing really wasn't up to the task. The path nodes don't align perfectly with the visual finish line which could give some strange results if there was a photo finish. To be fair these new checkpoints would only add 20 or so objects to a track but when I mentioned them to Eric he did talk about the shortage of object slots and that's why I decided to get down and sort that out. Actually it turned out not to be too bad, as in recent years the obstacles preventing me from changing to 32-bit object indices have been removed. Primarily it was the old 'optimiser' data that switched on and off objects as you drove around the track. It was huge data but now we use an occlusion octree that works in a different way and does not store the indices of individual objects.

There is more explanation in the log below. To illustrate the checkpoints update I have attached 3 screenshots. Because timing no longer relies on paths, it is interesting to note that open configs can now naturally do lap timing even without custom checkpoints being added. Paths still have some advantages such as instantly updated race position list and the colour coding for other cars on the small map, and these functions still work on configurations that do have a path.


Log of changes:

Skin downloads are now converted to DDS and saved from the download thread
- this reduces a graphical glitch when a skin is loaded onto a remote car
- simplified some texture loading code that was mixed up with skin saving

Cleaned up more code around texture loading and skin downloading
- the car's model is no longer rebuilt after its skin is downloaded
- instead the car holds a placeholder skin which is replaced behind the scenes

Support for ALPHA in section ends (tracks are made of segments between cross sections)

Fixed crash bug in the unused texture removal system (could remove some still in use)

Noticed a thread-related bug to do with setting the exposure while restarting
- game code does an 'illegal' D3D call that can cause corruption

Separated "set up lighting" into physical and graphical sections to fix the bug
- considered that this section of code has not yet been separated properly
- the physical part should be done every physics frame (sun could affect physics)
- graphical part needs to be done every graphical frame (shader constants, etc)

Realised that Eric was spammed with too many code-related debug messages in editor
- added a debug level option so he can see more relevant but not excessive messages
- used special macros to simplify the adding of messages for 3 different debug levels
- searched for and updated around 600 debug messages to use the new switchable system
- removed obsolete messages, e.g. a config without a defined path is valid these days

Encountered a thread-related crash, again during restart (clash with drawing humans)

Fixed a zoom bug in one type of trackside TV camera (probably was there a long time)

Removed another thread warning message that appeared in track editor (on undo or load)

Made car ambient shadows, lightmap lighting and headlight effect work in track editor

Considered a new timing system that uses proper checkpoints like in the layout editor
- existing timing is based on path nodes and is misaligned with visible finish lines
- Eric mentioned a concern with the number of objects in map approaching a hard limit

Converted object indices to 32-bit to increase the number of objects that can be added
- previous 16-bit indices only allowed a maximum of 65536 objects to be added to a map
- number includes objects, buildings, cameras, track cross sections and segments, etc.
- in the past the occlusion data relied on object indices and took up a lot of memory
- now we have a totally different occlusion system that storage issue no longer exists
- it took only a bit more than a day to update the remaining object indices to 32-bit

Moved onto the new system that allows accurate alignment of checkpoints and finish line
- started by analysing all path nodes over marked track segments to detect checkpoints
- this produces many checkpoints, often duplicates, e.g. a finish line for every config
- the duplicate checkpoints are combined and config switches enable them appropriately
- this leaves fully working checkpoints that Eric can adjust to improve accuracy
- worked on the editor side of it (the checkpoints are a type of invisible object)
- on the driving side, checkpoint detection use existing code for layout checkpoints
- timing is no longer path-based but paths have uses, e.g. instant race position list
- interestingly open configs can now do timing even without adding custom checkpoints
Scawen
Developer
Today I feel like a milestone has been reached. Nod

Until now there was a system in place so that if game code (such as multiplayer packets) needed to access D3D code, it could wait for the graphical frame to complete, then do whatever it had to do. That is because two threads must not do D3D calls at the same time as it could (would) cause corruption. One example of this system, when a player left the pits, the car's model was built. This was dealt with as described in the previous report. The car can now leave the pits immediately and the model is created when the car will be drawn. The final example was the creation or deletion of layout objects, when an incoming multiplayer packet was received. This was sorted out yesterday, so today I was able to remove that system completely (it only a small system, a couple of variables, a heavily used critical section and a warning message). The new rule is that game code is no longer allowed to access D3D code at all and therefore will never wait for a frame render to finish.

This morning I solved a related issue (where game code did access D3D) and then, after clearing leaves from gutters, I added "events" to the thread timing graph to illustrate the split car creation. As you can see in the attached image, the sync point every frame is now marked with a red triangle on the main thread. For this thread graph (which was in debug mode so things take a lot of CPU time compared with a release build) I timed one second, and called /ai to add an AI car half way through the second. You can see an orange triangle below the game thread, where the car is created. The orange block represent the processing of game packets, in this case it takes a while as the car is loaded and initialised (ready for physics).

Then, as mentioned before, the creation of the car's mesh (from editor model to game-ready mesh) takes place during the next graphical frame. The start of that event is marked by a cyan triangle above the main thread. That graphical frame takes a long time - you can see some missing sync points. But the interesting thing is how the game and physics code continue, fairly unaffected after a little catching up. I notice some longer physics frames during that long graphics frame. I'm not sure what the reason for that is but I'm not concerned about it right now.

I have crossed off quite a few more items off my note papers, so I'll start a fresh sheet with some of the last notes from other sheets and try to get through them. It feels like I'm getting near the end of the multithreading conversion.

Here's the log from Saturday to Monday afternoon:

29 Oct
Puzzling about the adding and removing of layout objects (layout editor is multiplayer)
- complication due to the fact they are changed in game code while drawing takes place
- seems easy to deal with adding objects: delay adding to draw lists until next frame
- deleting objects is more complicated as an object could be deleted while being drawn
- object buttons may be visible in layout editor (prefer not to copy all at sync point)
- one solution presents itself: save packets and delay add/delete until the sync point
- this prevents any issues with objects being created or deleted during the draw
- unfortunately it means objects may be changed out of sync with other game packets
- layout objects may define checkpoints or the existence of an autocross start point
- although the delay is only one graphical frame an OOS could arise from this
- seems quite rare, OOS would only occur with unlucky timing but it's not ideal
- possible solution for the game sync issue could be special packet for checkpoints
- in this scenario checkpoints would be worked out on host and broadcast to guests

30 Oct
Morning started with family leaf clearing session...
Implemented layout packet storage using expanding array - processed at sync point
- so this means layout objects are never added or removed during graphical render
- also solves any thread-related issues in the layout editor like selection buttons
- apparently rare multiplayer OOS potential issues will be dealt with by other means
- critical section covering graphics is no longer used by game code so can be removed
- as mentioned before there are still some calls to graphics code by game to be fixed

31 Oct
Removed system that allowed game thread to wait (using critical section) to call D3D
- it is no longer needed - the new rule is that game thread must never use D3D code
Removed issue: restart race while physics objects were moving called graphics code
- issue was deletion of graphical mesh - solution: delay deletion until sync point
- delayed delete system was already in use for moved objects returning to their spot
Cleared leaves from gutters - rain is forecast and we don't like overflowing gutters
Added 'events' to the thread timing graph - used to show sync point and car creation
Scawen
Developer
This week I've been removing the possible conflicts between the game code and graphical code threads. In the case of cars I have prevented the creation of anything graphical until the start of a graphical frame. Previously car creation involved D3D calls as the graphical model was created at that point. So the game code used a critical section to avoid clashing with D3D calls during the main render (or any other D3D activity). That meant the game thread would stall for that whole graphical frame, which is not what we want. So now the physics representation of a car is created immediately but the mesh is built only at the start of the next graphical frame (actually, only when that car will be seen in your view). Sounds simple but a lot of code had to be reorganised. The picture is further complicated when you consider game packets arriving with damage nodes (when a remote car hits something) and the model needs to be dented and updated. More detail and other reasons to rebuild meshes are mentioned in the log below.

I aim to remove all graphical critical sections in the game code so it never has to wait for graphics. Today I've been puzzling about layout objects, which may be added or removed in the game / multiplayer code. It's complicated as without protection they might be deleted during the render which could cause a crash. Possibilities such as delaying their adding or removal could cause an OOS (Out Of Sync) because the layout objects may define the timing system (by use of checkpoints or autocross start) and with unlucky timing that might cause a difference in results. So I'm thinking around the possible solutions.

Here's the update log for Sunday through to Friday:

23 Oct
Mainly day off, part of afternoon looking into things that might cost a bit in graphics
- slight change of code to allow profiler and render counters in the same dev version
- considering a future update to flags to update their motion with a compute shader

24 Oct
It's autumn half term holiday - morning started with family leaf clearing session!
On the multithreading list: cars being loaded wait for graphical render to end
- we don't want waits but needed as the new car's model may load textures (D3D call)
- obvious solution is to delay the creation of the graphical mesh until about to draw
- moved some code around to allow this and removed the wait (use of critical section)
- aero physics also depended on wing positions derived from the graphical model
- changed wing, undertray, aero centre positions to come from 'editor model' instead
- notes for next day - number plate creation when car is loaded also needs to be moved
- must investigate similar critical sections in other parts of multiplayer / game code

25 Oct
Had a look at these critical sections, wondering if all "EnterD3DCode" could be removed
- ideally game code would never never need to wait for graphics code to finish drawing
- although these waits are not common, their existence requires other critical sections
- for example main thread also needs critical sections to avoid the graphical conflicts
- if all CS on game thread could be removed then they will not be needed on main thread
- noticed a possible conflict if damage is being added while a mesh is being rebuilt
- started separating the physical (wheels) and graphical (mesh) parts of car damage
- added tiny critical sections to avoid using damage nodes while adding a new node
- this type of critical section doesn't cause threads to wait any noticeable time

26 Oct
A bit of a struggle updating the car mesh regeneration and damage system
- so many reasons for cars to be rebuilt or regenerated, it's quite confusing
- e.g. damage / skin download / delayed texture load / number plate change / editors
- also delayed texture load was an added complication meaning multiple types of reload
- decided to remove that entire system (that caused 'white cars' until texture reload)
- I have a better plan for delayed texture loads (reloading without mesh regeneration)
- approach was to simplify and unify all the regeneration methods until understandable
- finally mesh regeneration is never done by game code and only in the graphical code

27 Oct
Morning with family
Continuing to work through car initialisation, moved number plate init to graphics code
Noticed tyre vertex buffer init was also at car creation time - moved to graphics code
Helmet regeneration now follows similar coding pattern to car regenerate (but simpler)
Noticed that number plate info being set in car (by multiplayer packet) not thread safe
Found crash when regenerating car - snapshot copy of wheel refers to deleted model

28 Oct
Moved graphical elements of wheel (mesh pointers and matrices) to special structure
- avoids the crash noted yesterday evening as invalid pointers are not left around
- separate storage reduces the size of wheel to be copied at snapshot (more efficient)
Only one graphics critical section remains in game code - when adding layout objects
- the reason is because the graphical mesh for a layout object is built at that point
- investigation into removing that will start now as the aim is to avoid them totally
- there are still a few more noted points where graphical code is called by game code
Noticed and fixed shader error causing skids to be too shiny (related to vertex alpha)
Fixed another shader error for names above cars (related to recent alpha blend change)
Fixed a bug about position of a car exiting vehicle editor / now uses good height check
Scawen
Developer
One week later... where did that time go! Looking

I've been doing a variety of updates including a bit of off topic into shaders that is finished for now. Some cleaning up and organising. Sometimes I add a line of code in a convenient place. Then something conceptually similar comes along and I add it at the same place. Then that happens again and again and it's taking up a lot of space in the original source file. So it becomes a new system in itself, or at least something that should be packaged in its own function, and might end up with its own source code file. This time that happened for the "sync point" which was starting to get messy right at the end of the main loop. Some other clutter from Main.cpp went along into SyncPoint.cpp too. The Sync Point is a very useful place for LFS to do things, because for that tiny slice of time, only the main thread is running and the game/physics thread is waiting, so it's a safe time for things that need safety. As a random example, suppose the user refreshed controllers. It is done at the sync point, so the controller can't be updated half way through a game update. Anyway that was really just a minor change. Randomly I noticed that I wanted to use SHIFT+J or SHIFT+S sometimes in Garage and Free View but those keys weren't available. So veered off topic a while to sort that out.

I realised there were more ways to check thread-safety and did something for the "Physics" system which manages the interactions between and updates of cars and other moving objects. I gave it a protected access function like I had done for Race and Snapshot before.

Eric noticed an issue with something involving two layers of alpha textures. I ended up solving a newly introduced editor crash and also went full off-topic for a while adding a new shader which is really for a new type of transparent window on buildings that will be useful in a few places. It can use a single pass instead of two passes which is always preferable. But it was a bit confusing at first so I reorganised the shader definitions, to the point where I got a new understanding of them and was able to come up a with a way to reduce the number of shaders. It is to help avoid a phenomenon called the "Shader Permutation Explosion" which is where the number of shaders in use can get out of hand. Well LFS hadn't got to the point of an "explosion" yet but it was bugging me that some shaders were extremely similar and I found a way to use a few options (in the form of shader constants) to produce the different effects instead of increasing the number of shaders. The attached images show the reduction in calls to "SetPixelShader" so that is a slight saving (although I couldn't actually measure a change in frame rate with such small numbers).

Another quick change solved an audio problem and got something off a list of things to do. You can see in the attached image, the audio updates (shown in yellow) occur at approximately 100Hz and are not affected by graphical frame rate. This is the maximum update rate I can get with the current system and results in the most responsive sound, even if the graphical frame rate drops a bit.

From tomorrow I plan to try and get a few more things off lists as I'd like to get to the end of the multithreading subject as soon as possible.

Here's the diary of updates.

13 Oct
Wanted to remove the last remaining old-style reference to Race, in Misc options
- needed another "must do x" in the sync point in the main loop, but getting messy
- added a new source code file for things to do at the sync point, cleaned up a bit
- removed Race from external visibility, now only accessible through protected function
Off topic update: added SHIFT+J and SHIFT+S keys to garage screen and free view mode
- this also involved quite a bit of cleaning up and improving some packet functions
- also added SHIFT+P to free view mode (SHIFT+P/J no check for unsaved layout changes)

14 Oct
Some quick fixes around cars in garage and other screens accessing Race when loading
Went through a list of source code files to check if they accessed anything wrongly
Decided to update the 'Physics' system to use a thread-safe access check like Race
- the Physics system is the code that manages all the moving objects (Cars and Solids)
- like Race it must not be accessed from the main / graphics code at the wrong time
- not a big task in this case but again identified issues and improvements were made

15 Oct
Most of morning with family
Off topic: researched an issue for Eric - modeller object appeared different in game
- after the research my version crashed when exiting from Track Editor using X button
- it turned out this was due to a new 'thread-safe' method of exiting track editor
- but the correct exit function was not called when using the window's X button
- implemented a way to provide a special exit function for any screen, used on TrackEd
- found & fixed a bug exiting from the modeller in TrackEd, related to Map Squares
- continued to track down non-thread-safe code switching into and out of TrackEd

16 Oct
Morning with family
Off topic: tried a new shader to allow something like 'overlay' but transparent
- in current version of LFS an 'overlay' shader is available for black (solid) windows
- went through code to allow overlay with ALPHA materials and added a new shader for it

17 Oct
Fixed a bug reported by Eric and checked another bug that had already been fixed
Off topic: cleaned up the shader defines that control the creation of various shaders
- many of the shaders are from one hlsl file with various sections enabled or disabled
- the organisation of these switches was confusing and could be improved / simplified
- this was done carefully with plenty of testing so as not to break any of the shaders
- it is now a lot easier to understand the similarities and differences between shaders

18 Oct
Bit of leaf clearing from gutters in the morning - house below 3 large beech trees...
Some more renaming and organising of the shader names and specifications in game code
Investigation into possibility of using shader options to reduce number of shaders
- some of the shaders are so similar with just a couple of different multipliers

19 Oct
Change to sound/audio code, sound updates are done at maximum rate of 100 per second
Previous changes resulted in 1 sound update per graphical frame which solved an issue
- the original problem was that sound updates could delay the sync point and graphics
- intermediate solution was to only do sound on the next update after the sync point
- but that was less immediate and caused poor sound quality if the frame rate dropped
- new solution: update whenever possible but delay 1ms if main thread waiting for sync
- you can see the audio updates (yellow) in the attached thread timing graph
- I produce these timing graphs in the debug version to exaggerate the CPU time
- another thing to notice is that every 10th physics update is longer than usual
- this is due to only checking for contact collisions every 0.01 second
- checking against the environment was the main CPU cost of the 1000Hz physics
- so contact points that are not currently touching wait 10 updates before next check
A new shader update combines 6 groups of 3 pixel shaders into 6 shaders total
- the idea is to reduce the number of extremely similar shaders in memory
- changing from one shader to another involves a tiny time penalty so good to reduce
- the new version uses shader constants to create the different effects instead
- these minor differences were about shine level and diffuse colour depending on alpha
- as you can see in the attached images there are now fewer calls to "SetPixelShader"
- it's not a big change but means the new shader has not resulted in even more shaders
Last edited by Scawen, .
Scawen
Developer
Hi, here's some more progress to report. Again, I'll give a short summary and post the diary of updates.

Apart from continuing to make things thread-safe, I think the most interesting thing is a new system to make sure that a good part of the game code and data (the "Race" structure which holds Players and a lot of other data, for the game code) is not accessed by the graphics code, and also a smaller system to make sure the "Snapshot" (which is for rendering 3D and text) is not accessed by the game code. Considering that it would be quite impossible to find every line of code that is accessed in the wrong way, it's a great help to have these systems that can point out such issues whenever I come across them. It also helps me to devise more ways of restructuring the code to enforce thread safety.

Another interesting thing, at least to me Big grin is the live profiling graphs, which you can see in the attached images. LFS has always had one and it helps me to see which code uses a lot of CPU, (either because it's not well optimised or maybe there's a bug there). But it wasn't working recently due to the multithreading. I did have a CPU usage issue that forced me to sort out the multithreading version of the live profiler so I could track down the bug. Now I can select a profiler for the physics or graphics thread. The nice thing is these graphs are hierarchical, so I can click on the + buttons to see inside any section. I guess you'll know what I'm talking about if you have a look at the images. The first image shows the graphics thread CPU usage and the second image shows the physics thread CPU usage.

Here's the diary of updates:

6 Oct
Most of the day on home things (not LFS)
Afternoon / evening looked into the sound updates which can be improved
- in the most recent time graph you can see different length sound updates
- they are roughly in a 2:2:1 pattern, due to sounds being updated in 0.01s blocks
- it would be better to have variable length updates that can match frame lengths

7 Oct
Looked into sound improvements, changed the code to support variable length updates
- encountered various bugs, audio code is sometimes tricky to debug (due to timing)
- final bug was with the echo, realised there is a limit to the size of sound updates
- another obstacle I found is that the audio write point only moves in steps of 0.01s
- so it turns out I can't easily achieve the aim of variable length sound updates
- improvements have allowed me to split the sound updates over multiple physics frames
- another solution could be separate audio thread but it's too much work at the moment
Looked at FF rate - although 1000Hz is possible the options display still read 100Hz
Encountered (and fixed) thread-related crash when refreshing controllers in options
Fixed bug 'Flicker on car reset' which was thread related (wrongly reset draw values)

8 Oct
Morning with family
Looked into an issue where garage screen was initialised by game code when pitting
- that is against the rules of thread-safe behaviour in LFS code
- easily solved using a message from game code to main code to enter garage when safe
Found some bugs in Escape Menu - fixed them and improved the code for future proofing
Fixed thread-related and other minor issues with the Vehicle Editor
Moved position of "AutoJoin" which is for restarting autocross in multiplayer mode
Encountered a crash when second player joins race - related to drawing car alpha

9 Oct
Morning with family
Car alpha crash was due to removal of alpha LOD reset when car reset (bug fix 7 Oct)
- fixed by resetting alpha LOD to "do not draw" when car is created (not on reset)
Came up with another check to find code that is not thread-safe
- access "Race" structure (players, results, etc) through an access function
- this function can check that Race is only accessed from game code (not graphics)
- only trouble is the Race is accessed from around 900 lines of code... get started!
- stopped for the day after updating 400 of these lines to the new style access
- quick test already showed up two bugs for a quick fix and one more to note

10 Oct
Fixed yesterday evening's noted issue and carried on with converting Race references
Actually doing the changes makes me encounter various issues to fix along the way
It occurs to me that the Snapshot should also have the same type of protection as Race
- Race is for Game/Physics code and Snapshot (recently added system) is for graphics
Went ahead with restructuring Snapshot to an access protected version (fairly quick)
- Snapshot now contains a straight copy of the Race structure, excluding Players
- simplifies snapshot creation and makes it easier to convert code to use Snapshot
Stopped updating Race references for the day with only 164 remaining to deal with

11 Oct
Remaining references to Race have been updated to the new style after 2 hours
That is excluding some code related to skin resolution on the Misc Options screen
A race condition is revealed by the new check on switching from game setup to in-game
Also accesses to Race structure while drawing text in-game are revealed by the check
Fixed the text and entering game issues / made some changes to best lap announcement
MPR testing showed up bugs on restarting replay: crashes then invisible world issue
Clicking time bar at later point in replay is sometimes slow, sometimes fast
- learned how to reproduce the slow / fast versions of replay time clicking
- difficulty finding what extra processing takes place in the slow version
- built-in CPU profiler is currently unusable as it is not thread-safe
- looks like time to sort that out and that'll be another thing off the list
- profiler now selectable graphics / physics - used it to find the time clicking bug
Stop for the day, will fix "disappearing world on MPR restart" tomorrow

12 Oct
Fixed disappearing world on MPR restart - probably old bug unrelated to recent changes
- if layout objects were there, the occlusion octree was cleared when replay restarted
- needed to repopulate octree in that case - bug probably there since octree introduced
- for more info about the occlusion Octree see our September 2020 progress report
Back to fixing code that is not thread-safe (some identified by the new systems)
Garage was using (Player in) Race to decide which buttons to draw - now uses Snapshot
Spectate/Join wrongly used Snapshot copy of selected view (should use Game original)
Check for "Join reject" (first 12 seconds of race) needed Game and Snapshot versions
Something related to tyre warmers was called whenever a new Car was created in memory
Fixed that then spent a while cleaning up Car and Engine constructors for efficiency
Scawen
Developer
More gradual progress to report. I don't think this is very interesting reading to most people but at least it shows the sort of thing I have to look into each day.

Attached an image of the updated timeline graph. It has some new colours. The reddish brown colour on the graphics thread is while it has called D3D 'Present' to apply the fully rendered image to the screen. It seems to take a long time to do that each frame because it is with Vertical Sync enabled, so it has to wait for the screen refresh (avoids tearing, and there is no point in having a higher frame rate than the monitor's refresh rate). But even during that time, the graphics card may still be rendering. The end of the blue part is only where LFS has finished sending draw instructions. The nice thing is that, with multithreading, that wait is no problem now, the physics updates keep going on as you can see.

Some gaps in the game/physics thread I believe are because my computer is so old it only has two cores (although it is a good, smooth running PC). I guess the operating system or another program wants to do something, so Windows gives a time slice to that other process instead of continuing with the LFS physics. I believe this might not happen much on a quad core.

Another thing is the audio code (yellow). Although better timed now, seems to take some time and bunch the physics updates. But this is the debug version of the code, it's a lot slower than the release build. So it might not be a problem at all.

Here's the diary of updates for any who are interested. Shrug

30 Sept
Graphical timeline showing what happens on the two threads over one second
- displays concurrency and shows where one thread can hold up the other
- reveals processing time differences between physics updates
- shows the bunching of physics updates by audio updates
- suggests better timing of audio updates

1 Oct
Timing investigation guided by the new graphical timeline
Improved accuracy of the system timer using undocumented ntdll functions
Improved the timeline a bit by adding new elements and adjusting exiting ones
Adjusted the timing of audio updates to avoid interference with the sync point

2 Oct
Adjusted game code to allow interruption of bunched physics updates for a sync point
Noticed that downloaded mods and skins are not reloaded in the best place (noted)
Made wait for sync point *always* interrupt overloaded physics (avoids visual hangs)
Noticed that game reset while physics objects moving calls D3D code 'illegally' (noted)

3 Oct
Investigating a known fault related to timer resetting when no guests are connected
Noticed some sync check values had not been updated for the 1000Hz physics update
Made some general improvements, simplified the timer reset code and fixed the bug
Moved reload of downloaded mods and cars with updated skins to the sync point
Fixed an already noted issue with auto restart on exiting the pits in hotlap mode

4 Oct
Spent some time looking at ways to delay the loading of textures when loading a car
- it would be better not do so any D3D work while loading a car but it's complicated
- some of the physics code (aero positions) depends on the 3D model being built
- possible solution is for the model to be built by game code but delay texture loading
Put that on the back burner for a while and looked at VR in the multithreading system
- found some issues including time appearing to slow down
- realised this is due to an oversight in the changes made on 2 August
- corrected that, continued VR testing, fixed a couple of bugs
Continued VR testing, looking at timing graph, experimenting

5 Oct
Another VR day, did research, testing, tried a different approach from yesterday
Ended up with good smooth results on tracks where my computer is fast enough
Did a substantial test on VR and FF wheel, driving at Bancroft and Fairfield
Force feedback can also be output at 1000 Hz with the physics updates
Seemed to feel higher resolution on the G27, I guess it could be good on DD wheel
Read through lists of things to do, would like to get a few crossed off tomorrow
Last edited by Scawen, . Reason : not August... it's October - thanks Yisc[NL]
Scawen
Developer
OK, something graphical at last!

The attached image shows the first version of the thread performance analysis graph.

You can see 10 double lines, representing the two threads. These 10 lines really form one continuous timeline representing 1 second of time. Each horizontal line is 1/10 of a second. This is with vertical sync enabled (at 60Hz refresh rate).

The top line of each pair is the main (graphics) thread:

Grey - waiting to be able to do the sync (physics frame must finish)
Red - the sync point (windows messages and the snapshot)
Blue - the graphical render (drawing the world)

The bottom line of each pair is the game (physics) thread:

Green - each of the 1000 Hz physics updates (alternating shades of green)
Yellow - audio (car sound updates, approximately 100 times per second)

I think it's not bad for a first look. I can learn a lot from this and try to improve the timings. One thing would be to improve the timing and maybe frequency of the audio updates. At the moment they can sometimes cause the physics to bunch up and that can then delay the sync point, so the graphical render starts late. In an ideal world the green physics updates would be perfectly spaced, so that's something to have a look at. It's nice to be able to see how the physics and graphics run at the same time, instead of just having to imagine it.
Scawen
Developer
I've been keeping a diary of progress that some might be interested in, just for a little insight into the way the work goes. As development has continued I have gradually learned more systematic ways to track down where issues might come up. With increased understanding, my direction changes from haphazard to more directed and systematic. The thing with multithreaded code is that things can't be left to chance, because the type of bugs that can come up from race conditions are are too mysterious.

The main gist of the last week of development was to continue with the snapshot, including the physics objects and the smoke and skids. As that is nearly complete I've been sorting out a snapshot for the various lists that can be displayed, like the race position list, connections list and results. Always making notes about the things I notice during my travels through the code, and thinking of strategies to sort out the next thing.

Yesterday I noticed a possibility of deadlock which cannot be allowed. No matter how rare it might be, if it's possible then it will happen at some point. So I've noted a couple of things to do a slightly different way and then I'll be looking at the input side of things.

Here's the diary of updates since the previous post:

18-20 Sept
ViewCar (pointer to currently viewed car) separated into two copies (Game and Snapshot)
Changed Game::ViewCar to Snapshot::ViewCar wherever it is used for graphical purposes
More functions moved from "World" to "Game" along with associated variables

21 Sept
Continued with CarSnapshot implementation, added smoothed camera position
Temporary diversion: improved accuracy of camera direction vector storage
More use of CarSnapshot and included player name for display purposes

22 Sept
Added Player UniqueID to CarSnapshot and made ray checking thread safe (click on car)
Improved efficiency of CarSnapshot (moved SSPos/SSBodyMat to main Car structure)
Implemented snapshot copy of the list of Solid objects (moving physics objects)
Fixed new bug that could cause an object to disappear for the first frame when moved

23 Sept
Implemented snapshot copy of Smoke/Dust puffs (necessary as they move)
Implemented critical section to avoid adding/removing skid nodes while drawing skids
Fixed free view follow glitches by storing elapsed frame turns as part of the snapshot
Made turbines, flags and trees use the new elapsed frame turns
Fixed crash bug related to map squares when exiting track editor
Added some player-related values to CarSnapshot to enable thread-safe text displays
Implemented snapshot copy of live race position list and race results list
Updated car arrows on small map display using snapshot race position list

24-25 Sept
Implemented snapshot of connection info for the list of names (take over, send setup)
Worked through several info display screens to check thread safety and use of snapshot
Noticed a possibility of deadlock by acquiring game code lock while d3d lock is held
- this is because there is also some game code that could try to acquire a d3d lock
- for example when a car is created or layout objects are added a d3d lock is required
- apparent solution: avoid possibility of a game lock by main thread during a d3d lock
Progress on Multithreading
Scawen
Developer
This thread is for people who like technical insights into LFS development. It is probably too technical for most people, but I know that some do want to read this type of information.

As mentioned on the 20th Anniversary page I have been working on a multithreading system. As described on that page, we have been trying a 1000Hz physics update rate. It uses a bit more CPU than the old 100Hz physics rate (nothing like 10 times as much - but more information about that on another thread which I had to close).

The new graphics system also uses a lot more CPU power, primarily because of the shadow maps. People might think that graphics is all done by the GPU, but actually there is a lot of work for the CPU, sending instructions to the GPU (which objects to draw, using which textures and shaders, etc).

So with physics and graphics both consuming more CPU power, there is a great need for multithreading. LFS has always been a single threaded program, which is a good way to make a program when your CPU only has one core. But modern CPUs have more than one core, meaning they can run two or more threads simultaneously. Like two cooks building a complex cake, if they communicate a little, but not too much, they can get that cake made more quickly.

The physics and graphics have requirements that mean they need to run at a different rate. Graphics should run ideally at the refresh rate of your monitor, and physics should run at some high rate that eliminates stability issues. So for a typical monitor, graphics will run at 60Hz (it draws the world 60 times per second) and our experimental physics runs at 1000Hz (time steps of 1ms per physics update).

This suggests an approach where the graphics runs on one thread and the physics runs on another. This way, a CPU with at least two cores can get on with rendering graphical frames and processing physics updates at the same time. There are various advantages. For example, a few cars leaving the pits, but not seen, will not cause your graphical frame rate to drop below your monitor's refresh rate. There are other ways to do multithreading but I am aiming for this traditional approach.

That's great but it's actually a very complicated process to try to get the code separated onto two threads, and never looking at the same data at the same time. As a simple example, the graphics might be half way through drawing the cars, when the physics updates some of the cars, so they glitch forwards relative to other cars. Or worse, the graphics may be drawing an image from one car, the "view car" and that player goes to the pits, suddenly the "view car" is invalid data and the graphics code accesses the memory that is no longer allocated. Or maybe the user clicks a button and some data is added to the multiplayer packet system, at exactly the same moment while the other thread is writing to that system, causing data corruption. I can't describe all the examples but there are so many ways to go wrong unless great care is taken to avoid such issues.

The general principle for the coordination of graphics and physics threads, is that the 'game code' that does the physics, can freely continue most of the time. But when the graphics code wants to draw a frame, it requests a 'snapshot' of the current game state from the physics system. It may have to wait a small amount of time (something less than 1ms) for the physics to finish its current update, then the physics must stop for a tiny slice of time while the snapshot is obtained. That contains all the positions and rotations of the cars, wheels, suspension, physics objects, smoke, skids etc. Anything that can be changed by the game code. Let's call this a 'sync point'.

I made a few false starts on separating LFS as required. One of the earliest approaches was to split the entire program into a physics section and graphics section. But it got out of hand and I reverted around two days of coding. Then I tried something where only the game setup screen and in in-game code would be multithreaded. Running into too many problems, I reverted this attempt as well. There was some other attempt as well but it's a bit of a blur, I can't really remember. But I did learn things while making these false starts. In the end I have had success with an approach that only starts a physics thread when LFS enters the in-game mode. Even the game setup screen stays unchanged. This approach causes the minimum disruption, only changing the code that actually needs to be changed.

I started by preparing parts of the code for this separation. For example, the game timer used to be part of the main loop. I realised there were now different requirements for the graphics timer and the game timer, and that the game timer would need to be run on the game thread, so that code was duplicated and specialised into separate systems. Other code was moved around and restructured in preparation for the multithreading. The part of the code that actually processes multiplayer packets and does physics updates was moved into a separate file, along with associated variables. Various functions needed to be moved over into that separate game file. It's confusing work but the aim was to move all the "game and physics" code and variables into that new file, while leaving the graphics code in the original file.

With the separated code seeming to work as before, it was time to set an option to run that code on a thread. At first that thread was extremely protected from collisions with the graphics thread. It had to be protected so much that no graphics and physics would actually be running at the same time. However, game code could continue to run after the world was drawn, while post-processing was taking place and while LFS submitted the finished image to be applied to the screen. That was enough to cause some thread-related issues and cause me to develop some protection code, that can catch some bugs before they happen. For example, if the game code does some D3D work, for example deleting the mesh of a physics object that stops moving, or loading a car, while the graphics system is also asking D3D to do something, there is a problem and this will sometimes result in corruption. Not all the time, but randomly, when the timing happens to be wrong. So my protection code was designed to make sure the game code never does D3D work unless it has entered a "critical section" that allows it to do so (when the graphics code is in a moment when it is not drawing). Each time a critical section is used, there is a performance issue, because one thread has to wait for the other. So I devise ways to avoid their use when possible. For example when the game wants to delete a car or physics object, now it doesn't immediately delete it. Instead, it adds that object to a list of objects to be deleted. The graphics code will then delete that at the sync point that occurs every frame, just before getting the snapshot for the next frame.

With most issues sorted in that first, non-concurrent, version of actual multithreaded code, it was time to try to get the game code (multiplayer and physics) running simultaneously while the graphical images are drawn. It was very encouraging to see that this worked, to some extent, on the first attempt. But it displayed the expected thread-related issues. I remember the car flicking forward and backward a bit, and a strange effect in the mirror, where the displayed image in the mirror actually showed the back of the mirror, as the mirror view was somehow detached from the actual location of the car. As I say, entirely expected and so I set to work on the "snapshot" code.

The first stage of the snapshot code was to create a list of all the car objects visible at the sync point that occurs every graphical frame. And in all these car objects, store the position and rotation of the main car body. Then make all the graphical code refer only to that list of cars, and only use the "snapshot copy" of position and rotation, and never to the "physics version" of those values. This had the desired effect of stopping the cars jerking around and stabilising the mirrors. Then I saw that there was a tear in the wheel of the car I was viewing. This must be as some values of that wheel were changing, while it was being drawn. To me as a programmer, these bugs are actually quite exciting as they show the threads are really happening. Well I did know that something was going to go wrong with the wheels as they had not been included in the snapshot, and they have their own rotation, position, suspension compression, contact point, contact patch deflection, etc. In fact much more than the actual car body. I started to extract the necessary wheel variables into the snapshot, but reverted my code when that all got out of hand. The following morning I simply included a snapshot of the entire wheel structures, in the car's snapshot, and the wheel problem disappeared.

It seemed that the next step is to do the same for the physics objects, but then I started to encounter some rarer bugs that came up occasionally when I entered the garage screen. Most of the time things worked, but when a bug comes up it's best to sort it out immediately, as with these thread-related issues the bug is not guaranteed to come up every time. The trick is also to recognise a bug as an entire "category" of bugs, and go through the program removing all of those same types of bugs. Another one was when I tried to exit using the X button on the window, and the game froze. I thought it might be a deadlock but actually graphics and physics threads were still running. After some looking around I decided it was probably something to do with adding an "exit game" packet while other packets were being added, or removed, or something... I don't really know as it happened earlier and obviously wasn't something that would be caught in the debugger. So I started work on another protection system which will catch bugs of that type, when the graphics or UI code adds multiplayer packets, that now can only be done in a relevant critical section.

So that's where I am at the moment, the next thing is to take care of the "view car" which is set by the graphics code but can might be changed mid-draw with disastrous consequences. Presumably the solution is to store the view car pointer as part of the snapshot.

As for results, I have not done any performance testing yet. I'm more interested in improving the code structure and removing all the known ways things can go wrong, and also the unknown ways, each time they come up. I got some idea that good things are happening when my frame rate was very limited by being in the debug version (nowhere near monitor refresh rate) and I did a couple of /ai calls. Then overall CPU usage went up but the frame rate stayed constant, as the AI cars were not on screen. It was encouraging to see that the physics processing had increased without affecting the frame rate.

I'm interested in detailed performance monitoring. I'd like to do a timeline for the two threads with some accurate timings, so there are two lines across the screen, and you can see the length of time the graphics thread spent drawing, and for the physics thread, how much time it spent on all those small physics steps and audio updates (which are currently done on the physics thread). And the sync point. So we can start to see how things are really happening, how steady the physics steps are and so on.

That's all for now. I'll keep the thread closed. Partly because some users chose to use previous progress threads as an outlet for their personal issues. But more positively, the next progress post can be added directly after this one and the thread will be kept clean. It's a new approach that may have good results. I don't really need to discuss anything or receive ideas and input, because there is plenty to be getting on with.

Thanks for reading! Smile
20th Anniversary!
Scawen
Developer
Hello Racers,

It is the 20th anniversary of Live for Speed becoming well known! According to various sources, it was on 18th August 2002 that Demo Test 0.04k first became known to more than a few people. It was very exciting to see the reaction to this new racing simulator that seemed to have appeared from nowhere and was quite different to what was available at the time. It had a focus on multiplayer racing. Despite synchronisation issues, it was already a lot of fun to race around Blackwood, with up to 8 drivers, in an XF GTI, XR GT, or XR GT TURBO.

If you'd like to try 0.04k it is available on our downloads archive page. It does not connect to the master server but it is possible to connect to a host directly by IP address.

LFS has come a long way since 2002, with 9 track areas now available and a huge variety of cars created by racers using the new mods system. Of course, there is more to come, notably a new graphics system and new tyre physics. The new graphics system includes dynamic lighting and day to night transitions. The tyre physics update is more realistic and accurate for a better driving experience.

We decided to show a few pictures of some track updates that Eric has been working on and share some technical details about the ongoing development in the physics system.

Please visit the 20th Anniversary page to see the screenshots, read about the development and watch a few short video clips.



Thank you for all the support over the last 20 years!

- LFS Developers
Scawen
Developer
In my opinion LFS is to blame, rather than any hardware issues. Or a sort of combination of the Oculus software being a bit odd and LFS not fully adapted to it. Though that can probably be overcome by a very fast computer, you could still argue it's LFS's fault in some way.

For example the call where LFS submits the finished render target to the Oculus software, blocks for quite a while each frame. That means by default LFS would not be able to do anything at all while it simply waits for Oculus to return. That is the method that Oculus uses to force the program to stay at the correct frame rate. For the record, this is different from the SteamVR method, where the blocking is done on a separate function where the game asks for the head position for the next frame.

To try to avoid this wait, LFS uses a thread to submit the image. It allows LFS to continue with other tasks until Oculus says it's OK to proceed. LFS then waits at another point. I am not really sure about the interaction between this thread and the other part of the program. Also there is complication due to the fact that LFS renders in Direct3D 9 and submits a shared texture to Direct3D 11 as used by Oculus or SteamVR.

In my opinion it would be much better to use a separate thread for the render and the physics. I believe the VR driver software for Oculus and SteamVR are designed to be used in this way. So the graphical thread would continually create images and submit them to the VR system, while the physics thread does its own thing.

Going quite off topic...

Converting LFS to be multithreaded in that way is a big task and I am working on it, or at least looking into it, right now. It would never be done for the existing public version, but in the development version I have made one big step in that direction. As recently discussed on two threads that had to be closed, our new version is currently running the physics system at 1000Hz. This brings some benefits already although this is still done in bursts. One graphical frame, a burst of physics frames (on one thread). The best thing would be if the physics could continue at a steady rate rather than running in bursts. The next big change is to try and separate all the game screens / modes / processes or whatever you want call them, into a separate 'render' and 'process' function. All the LFS screens currently have their processing (if any) and render (often just buttons) in a single function. I believe these should all be separated into two functions so that processing and the render can be cleanly separated. On most screens this should be straightforward, but for example the game setup screen also processes the multiplayer system so that is a bit more involved. The in-game world is as you would expect, the biggest one of all as it does a lot of complicated graphics and multiplayer / physics processing. If that separation goes well then the graphics (including UI) system will be closer to being separated out into a separate thread.

Back on topic...

I don't really expect to make any improvements to the existing public version to make it work better in VR. Fundamental issues such as the single threaded nature and the use of Direct3D 9 are significant complicating factors. However for various reasons I am working on what I believe is the proper solution, in the development version with the new graphics and physics systems.
Scawen
Developer
Thanks for the information.

Good to hear LFS keeps on working with new headsets, through OpenVR.

I don't have any plans for OpenXR support at this time and I would hold off from such updates as long as possible, while there are so many other things to work on. So I hope OpenVR support keeps going for a long time.

I've been working on a 1000Hz update rate for the physics that allows better time steps between graphical frames so that should help with VR if I can manage to sort out the remaining issues.
Scawen
Developer
Quote from johneysvk :...but at this point the new physics have been promised for almost half of my life...

Very interesting... not.

This thread had actually become a place where I was relaying information about interesting updates to the graphics system. I was thinking of it as somewhere I could write minor updates without going the way of full progress reports. Thumbs up

But for some very strange reason, a few people decided to turn it into a new thread to bash the LFS developers. Some people have some very strange personal issues and should really have a think about that.

We have reached an entirely new level of weirdness here, where a few people are actually attacking me BECAUSE I AM DOING the very thing they want me to do. Confused

Thanks to the people who offered support and ask me not to get discouraged. But the weird people do put me off somewhat. It's quite a bad feeling to be thinking about something for ages, trying experiments, getting good results, thinking "this will be nice to tell the community" then receiving general off-topic insults on a thread for absolutely no reason.

Previous comments have not managed to stop the weirdos coming out, so I'll now close the thread, because it'll be more peaceful to keep on with the updates, without getting notifications about new posts. I have to read the comments, because any new post might have been one of the majority of people who were actually interested in updates. But too often it's one of the people who just want to spoil it for others because of their own personal problems.


Final update:

I managed to reduce the CPU usage for the calculations a lot in the 1000 Hz version, mainly by making special code to avoid the intersection checks whenever possible, and also reducing the frequency of the detection for contact points that are not currently in contact. So far the intersection checks for 10 cars at South City are reduced from 20.3% to 6.1% of CPU and it does not get too much worse under the flyover. I have a plan to try improving the numerical efficiency of the detection code.

As for the subupdates, the increase in that computation wasn't so much related to the cache as I had thought. In fact the actual "subupdate" part for 10 cars increased only from 3.3% to 4.2% of CPU. The main extra work is explained by a part that is done each physics frame and comes after the subupdates, which increased from 0.5% to 3.3% of CPU because it is done 10 times more frequently. I'm sure some improvements can be made in there.
Last edited by Scawen, . Reason : said 'actually" too many times :-D
Scawen
Developer
Hi, I had a look into this before the last official version and was able to reproduce the issue but we were out of time and I couldn't think of a quick solution. As far as I can understand, the trouble is that the mouse wheel cannot be 'held down' like an ordinary gearshift key or button. It is only 'held down' for such a short time (I think it was a set number of physics frames, or maybe only 1 frame) that the engine may not be sufficiently unloaded to allow the shift at that moment. I'm not really sure what the solution should be. Maybe it needs special code when a mouse wheel is assigned to shifting, so that instead of doing the normal thing (holding down a fake button/key for a set number of frames) it should do some sort of semi-intelligent thing like holding down a fake key until a gear change has occurred, but for a maximum of 1 second, or something like that.

Just to explain another way in case my text above made no sense - for clutchless upshifts you are really supposed to hold the upshift key/button on, then release the throttle momentarily, and at that point you release the upshift key/button. The mouse wheel as it is currently coded is not suitable for this as there is no concept of "holding the button on".
Scawen
Developer
I made a step forward in tyre physics last week. Although there is still a lot to do, I thought it would be good to try a test of the 1000Hz updates this week (nothing to do with tyre physics but may help with separating physics and graphics onto separate threads, along with other advantages). I was able to get a first version running in a day and worked another day searching through references to 'turns' and fixing various issues where the code had assumed that each turn was 0.01s. Now it's coded in a flexible way so I can change the update rate and recompile, to get comparisons between the 100Hz and 1000Hz versions. Actually there's a bit more searching to do but I was able to run some tests.

The good results:

The moving image is noticeably smoother. Different people have a different sensitivity to the stutter that results from the mismatch between graphical frame rate and physical update rate. As mentioned before, with a 60Hz frame rate and 100Hz physics rate, the graphical frames have physics updates like this: 2, 2, 1, 2, 2, 1...

This is known to be a worse problem in VR, with 90Hz frame rate, there are 8 graphical frames with 1 physics update, then the 9th graphical frame has 2 physics updates. So there is an extra step 10 times every second which is unpleasant when you look left or right out of your car and see scenery moving by.

That stutter can be reproduced without VR by a simple camera movement test. In full screen with vertical sync enabled, park a car in the open (e.g. at autocross) enter free view mode and look down at the car. Use left mouse button to move the car in circles or from left to right. You can see a sort of stutter or blurring at the edges of the car, or with the paint lines on the road.

With the 1000Hz version, the physics updates per graphical frame are 17, 17, 16, 17, 17, 16... which seems a lot smoother and the stutter is no longer noticeable.

Also super slow motion looked nice. Even when slowed to 1/8 speed, the physics frame rate is still 125 Hz which is more than the frame rate, so the slow motion car looks smooth.

Physics checks with the environment are more frequent, for example at 100mph we are at about 45m/s so with 100Hz updates, environment checks are every 45cm. With 1000Hz updates the environment checks are every 4.5cm. This looked good in force view as the AI driver's wheels drove over the kerbs though I have not tested FF. I don't expect to feel a difference but it could be good for people with high end DD wheels.

The bad results:

So far the CPU usage is too high. I ran a test with 10 AI cars at the start line in South City. As expected the environment checks used 10 times the CPU. The movement update also took more CPU time due to not being in a tight loop (although there are the same number of movement updates, known as sub-updates in the 100Hz version). This is assumed to be related to the cache. It's more efficient when the CPU runs a tight loop on the same data, compared with going through all the other cars and then going through all sorts of other code and data before coming back to the same data again the next frame.

Results when changing from 100Hz to 1000Hz:

10 cars on grid at new South City, physics code % of CPU time

environment checks - 2.2 up to 20.3
movement update - 3.9 up to 9.40

What next:

The movement update may be improved a little because there are no actual sub-updates, some things could be done more efficiently but I do not expect a very significant improvement.

The environment check CPU time increase is not acceptable. This 20% CPU usage is only with 10 cars and it gets far worse when the cars go through the underpass. But nearly all these environment checks are actually parts of the car (contact points and wheels) checking for collisions with nearby objects and not getting a collision at all. This suggests there is a lot of scope for optimisation. The idea is to avoid the detailed collision check in most cases if there isn't any chance of a collision. Of course, this is done to some extent already but a more accurate method is needed. The first thing to try is "Oriented Bounding Boxes" for the track segments. It's the obvious choice as it could reduce a lot of checking against fences, barriers and road surfaces. I'll need to try that and see how it goes before trying to think of other types of optimisation.
Scawen
Developer
Good question but the answer is quite unknown at the moment.

In fact it's not really 10 times the workload, although there is certainly more workload. The current LFS does 'subupdates' within the physics updates. The main reason for that is the wheel object suspended between a strong spring pushing down (suspension) and another stiff spring pushing up, the physics needed a higher update rate to avoid instability in that and I think on some other areas too.

In the public version that subupdate rate is 20 times the overall physics rate. So there is a part of the car already updating at 2000 Hz. In the development version there are 10 subupdates so it's already running at 1000 Hz.

But the ray checks vs world objects (and other cars) only happen at the base physics rate, so that is only at 100 Hz. This part might be 10 times the workload, as you suggest. There is also an advantage in the existing version that the subupdates are done as a tight loop on an individual car so I assume this is good for cache access. I'm sure that expanding the tight subupdate loop into full physics frame loops will be less efficient for cache hits.

Diagram:

Current:

0.00 - Environment check for all cars
Physics update for car 1 (10 subupdates)
Physics update for car 2 (10 subupdates)
...
0.01 - Environment check for all cars
Physics update for car 1 (10 subupdates)
Physics update for car 2 (10 subupdates)
...
[0.02s elapsed]

Proposed:

0.000 - Environment check for all cars
Physics update for car 1 (1 subupdate)
Physics update for car 2 (1 subupdate)
...
0.001 - Environment check for all cars
Physics update for car 1 (1 subupdate)
Physics update for car 2 (1 subupdate)
...
[0.002s elapsed]

I really can't guess how much more work this would be. The environment checks may be 10 times, as you pointed out. I think some optimisations might help with this. The subupdates shouldn't cost any more calculations but presumably will be slowed by memory access as the 'subupdates' are no longer done on a tight loop for a single car.

I think the way forward is to go through the program, adjusting it where necessary so that I can test the two scenarios above with a simple program change (update frequency & number of subupdates). Then test the CPU usage for the physics loop and see how it compares. That sounds simple but as you may imagine, I haven't always put in a suitable multiplier when trying to work quickly to release updates. There is some code around like "do this for 100 updates" which I knew would take 1 second. But now such code needs to be changed to the equivalent of "do this for 1/update_time updates" etc. It shouldn't take too long to get for a first test just to see how the CPU usage is affected. Hopefully it's just a search for the word "turns" and look at each one to see if it needs a fix.

The word "turns" (not case sensitive) appears 671 times
The word "Turn" (case sensitive) appears 785 times

Unfortunately the word "turn" in lower case is part of the word "return" which appears 9687 times. Schwitz But don't worry, I should be able to devise reasonable strategies to find the relevant lines to check.
Last edited by Scawen, .
Scawen
Developer
I kept thinking though. Remembered there may be a good "sledgehammer to crack a nut" type solution. This would be, for the snapshots, store a FULL copy of all the car variables (using direct copies of the entire car and wheel structures). These snapshots can be *written* by the physics system and *read* by the graphics system, but are created without too much brain power, just copy everything. Well, not *everything* for example you wouldn't copy the mesh from one frame to the next. So even this sledgehammer style "copy a snapshot of car" function would need some care and there is always the complication of things like, player spectates car, so car is deleted. But graphics system is still in the process of rendering the car -> crash or mysterious errors.

Some design considerations might cause quite a change. For example, the current physics frames are at 100 Hz. So to render at 60 Hz or any other frame rate, the graphical frames should be an interpolation between two physics frames. This would solve a well known problem that is particularly bad in VR. But there is an alternative solution - do physics frames at 1000 Hz instead of 100 Hz. Then store only the snapshots for the relevant physics frames and render only the nearest physics frame, not interpolated.

For example, with physics at 1000 Hz, rendering at 60 Hz graphically, we could use physics frames with gaps (in ms):
16, 17, 17, 16, 17, 17 (that represents 6 graphical frames in 0.1s).
I don't know if this slight difference between frame times would be humanly perceptible, though I'm sure it would be a lot smoother than any current version of LFS. For example, current LFS rendered at 60 Hz has gaps (in ms):
10, 20, 20, 10, 20, 20 (6 graphical frames in 0.1s).

Anyway, as I said, it's an interesting subject. Smile

But I don't have to think about that now, it's not tyre physics. Big grin
Last edited by Scawen, . Reason : typo
Scawen
Developer
I'd still like to do that (physics and graphics on separate threads so they can be processed simultaneously by different CPU cores) but I'll reconsider when the tyre physics seems acceptable. I wouldn't like to delay the release purely for that but it might be important for performance reasons. The new LFS does a lot more CPU work for the graphics. Although the GPU does most of the work, the CPU needs to make a lot of decisions about which objects to draw into the shadow maps. The CPU must instruct the GPU and it would be great if that graphics could use a separate CPU core so it doesn't need to share a single core with the physics.

The trouble with that (as I see it) is the separation of the cars (and other graphical elements, like skids, dust, etc) into a physical part and a graphical part. At the moment a car and its wheels have graphical and physical things all mixed in together without a clear separation. Some variables are purely physical, some purely graphical, some are shared between both. There needs to be a very good separation so the physics can continue to proceed, adjusting the car's state such as suspension, wheel rotation, body position, while the graphics system can render all the cars for one particular physics frame (or an interpolation of physics frames). It cannot simply render a car that might be half updated, part way through a physics frame. So before or after each physics frame is calculated, a 'snapshot' of each car must be stored, with enough variables to render every aspect of that car.

Because a car contains hundreds of variables, it's not a simple task to create that snapshot system, where a clearly separated graphics system reads only the snapshots, without access to the car variables that it always used in the past.

It sounds like a really interesting programming task though, but is quite a lot of work do do, as I am reminded when I look through the car and wheel structure definitions.
Scawen
Developer
I've said before but will explain again as I know not everyone would know this:

The old tyre physics does not exist in the new version of LFS. Too many things were changed - the way the tyres work, the specification of the tyre compounds, the AI drivers, various abstract things, etc. At some point I found it impossible to keep two versions of tyre physics in the one program. There is no file "TyrePhysics.cpp" or something like that. Contributions to the tyre physics are spread around many files and systems within the game code.

So it would be a lot of work to bring the old tyre physics back into the new version of LFS. It's a possible option but would be madness to do that right now. Going back into the past, and making myself suffer for no reason at all.

What seems the right thing to do is try to make the new tyre physics work properly, then all's good and we move into a new era graphically and physically. Anyway Eric still has work to do on various tracks so it's not as if we are just waiting for me. Eric is of course free to comment if he wants to but I don't want to bother him for a graphical progress report at this time. My focus is the tyre physics and that's all really.
FGED GREDG RDFGDR GSFDG